package com.isecommerce.application.datawizard.dao;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.*;

import com.isecommerce.application.datawizard.FormatGenerator;
import com.isecommerce.application.datawizard.OutputCSVFileInfoManager;
import com.isecommerce.application.datawizard.RAWCSVFileInfoManager;
import com.isecommerce.application.datawizard.StandardFormatInfoManager;
import com.isecommerce.application.datawizard.entity.OutputCSVFileInfoEntity;
import com.isecommerce.application.datawizard.entity.RAWCSVFileInfoEntity;
import com.isecommerce.framework.entity.*;
import com.isecommerce.framework.util.LogWriter;
import com.isecommerce.framework.util.Utility;

public class DwightSchoolUSFormatConverter implements FormatGenerator{
	
	private final String[] LANGUAGE_ID = {"-1","-9"};
	
	private final String THUMBNAIL_IMAGE_PATH     = "images/thumb/";
	private final String FULL_IMAGE_PATH          = "images/full/";	
	private final String CATEGORY_NAME_COMBINATOR = "_";
	private final String ATTRIBUTE_NAME_VALUE_SEPERATOR = ":";
	private final String CUSTOM_FIELD_VALUE_SEPERATOR = "|";
	 
	private final int STEP2_COLUMN_COUNT       = 17;
	private final int STEP3_COLUMN_COUNT       = 5;
	private final int STEP5_COLUMN_COUNT       = 11;
	private final int OFFER_PRICE_COLUMN_COUNT = 6;
	
	//                                         {Identifier, Display Name}
	private final String[][] IDENTIFIER_DEF = {{"MG", "GIRLS"},
											   {"MB", "BOYS"},   
											   {"",   "UNISEX"},											   
											   {"",   "DWIGHT ACCESSORY"},
										   	   {"BLAZERS",         "BLAZERS"},
											   {"SHIRTS_POLO",     "SHIRTS & POLO"},
											   {"SKIRT",           "SKIRT"},
											   {"PINAFORE",        "PINAFORE"},
											   {"PANTS_SHORTS",    "PANTS & SHORTS"},
											   {"OUTER",           "OUTER"},
											   {"PE",              "PE"},
											   {"SOCKS",           "SOCKS"},
											   {"BACKPACKS",       "BACKPACKS"}
											   };
	
	//                                     {SEQ, attributeIdentifier, attributeName}
	private final String[][] ATTRIBUTES = {{"1", "COLOR", "COLOR"},
										   {"2", "SIZE", "SIZE"}};
	
	private final String[] HEADER_STEP2_PRODUCT = {"product",
			                                       "partNumber",
			                                       "parentPartNumber",
			                                       "type",
			                                       "inventory",
			                                       "markForDelete",
			                                       "height",
			                                       "length",
			                                       "width",
			                                       "sizeMeasure",
			                                       "weight",
			                                       "weightMeasure",
			                                       "field1",
			                                       "field2",
			                                       "field3",
			                                       "field4",
			                                       "field5"};
	
	private final String[] HEADER_STEP2_PRODUCT_DESC = {"productDescription",
			                                            "partNumber",
			                                            "languageId",
			                                            "displayName",
			                                            "shortDescription",
			                                            "longDescription",
			                                            "published",
			                                            "thumbnail",
			                                            "fullImage",
			                                            "type",
			                                            "","","","","","","",};
	
	private final String[] HEADER_STEP3_CATEGORY_PRODUCT_REL = {"categoryProductRelation",
																"categoryName",
																"categoryMemberId",
																"partNumber",
																"sequence"};
	
	private final String[] HEADER_STEP5_ATTRIBUTE = {"attribute",
													 "parentPartNumber",
													 "languageId",
													 "attributeType",
													 "attributeName",
													 "description",
													 "description2",
													 "sequence",
													 "field1",
													 "attributeIdentifier",
													 ""};
	
	private final String[] HEADER_STEP5_ATTRIBUTE_VALUE = {"attributeValue",
													 	   "itemPartNumber",
													       "parentPartNumber",
													       "languageId",
													       "attributeType",
													       "attributeName",
													       "attributeValue",
													       "sequence",
													       "field1",
													       "attributeIdentifier",
													       "attributeValueIdentifier"};
	
	private final String[] HEADER_OFFER_PRICE = {"PartNumber",
		 	                                     "Price",
		 	                                     "CurrencyCode",
		 	                                     "MinimumQuantity",
		 	                                     "MaximumQuantity",
		 	                                     "Delete"};
	
	private StandardFormatInfoManager stdInfoM;
	private RAWCSVFileInfoManager     rawCsvM;
	private OutputCSVFileInfoManager  outputCsvM;
	
	private ArrayList<ArrayList<CSVEntity>> arrSTDFile;
	private ArrayList<CSVEntity>            arrIdentifierList;
	private ArrayList<CSVEntity>            arrAttributeList;
	
	private HashMap<String,ArrayList<String>> mapItemPartNumberList;
	
	private LogWriter logger;
	
	private void init(){
		
		// Init logger
    	this.logger = LogWriter.getLogWriterInstance("DATA_WIZARD", LogWriter.DEBUG, new PrintWriter(System.out));
    	this.logger.setOwner(this.getClass().getSimpleName());
		
		CSVEntity csvE = null;
		
		// Init repository for file content
		this.arrSTDFile = new ArrayList<ArrayList<CSVEntity>>();
		
		// Init identifier list
		this.arrIdentifierList = new ArrayList<CSVEntity>();
				
		for(int i=0; i<this.IDENTIFIER_DEF.length; i++){
			
			csvE = new CSVEntity(this.IDENTIFIER_DEF[i].length, ",");
			
			for(int j=0; j<this.IDENTIFIER_DEF[i].length; j++){
				csvE.setItem(j, this.IDENTIFIER_DEF[i][j]);
			}
			
			this.arrIdentifierList.add(csvE);
			
		}
		
		// Init identifier list
		this.arrAttributeList = new ArrayList<CSVEntity>();
				
		for(int i=0; i<this.ATTRIBUTES.length; i++){
			
			csvE = new CSVEntity(this.ATTRIBUTES[i].length, ",");
			
			for(int j=0; j<this.ATTRIBUTES[i].length; j++){
				csvE.setItem(j, this.ATTRIBUTES[i][j]);
			}
			
			this.arrAttributeList.add(csvE);
			
		}
		
		// Init item part number map
		this.mapItemPartNumberList = new HashMap();
		
	}
	
	public void generate(StandardFormatInfoManager stdInfoM, RAWCSVFileInfoManager rawCsvM, OutputCSVFileInfoManager outputCsvM){
		
		// Assign manager
		this.stdInfoM = stdInfoM;
		this.rawCsvM = rawCsvM;
		this.outputCsvM = outputCsvM;
		
		// Initialize global repository
		this.init();
		
		this.printSepLine(LogWriter.INFO);
		this.logger.log("[EXECUTE MCM US/JP FORMAT CONVERTER]", LogWriter.INFO);
		
		
		// Get STD file (loop for multiple std file loading)
		this.loadStandardCSVFile();
				
		this.logger.log("[CONTENTS ARR]\n" + this.getProductRawData(), LogWriter.DEBUG);
		this.printSepLine(LogWriter.DEBUG);
		
		// Get reference info
		// skipped
		
		// Generate Item Part Number (SKU) from given product information
		this.generateItemPartNumberMap();
		
		// Write each output format
		OutputCSVFileInfoEntity outE = null;
		
		for(int i=0; i<this.outputCsvM.getFileCount(); i++){
			
			outE = this.outputCsvM.getCSVfileInfoByIndex(i);
			
			switch(i){
			
				case 0: // STEP2					
					generateStep2(outE);
					break;
					
				case 1: // STEP3
					generateStep3(outE);
					break;
					
				case 2: // STEP5
					generateStep5(outE);
					break;
					
				case 3: // OFFER_PRICE
					generateOfferPrice(outE);
					break;
					
				case 4: // ASSET_REFERENCE
					generateAssetReference(outE);
					break;
									
				default:
					this.logger.log("[OUTPUT CSV DEFINITION NOT EXIST]", LogWriter.INFO);
			}
			
		}
		
	}
	
	private void generateItemPartNumberMap(){
		
		this.logger.log("[ITEM PART NUMBER MAP] ", LogWriter.INFO);
		
		// Get data with CSV entity formed
		ArrayList<CSVEntity> stdData = this.getProductRawData();
		CSVEntity stdE = null;	
				
		String curAttrIdentifier = null;
		ArrayList<String> curAttrValList = new ArrayList<String>();
		
		int itemPartNumberCnt = 1;
		ArrayList<String> curItemList = new ArrayList<String>(); 
		
		
		// -------------------------------------------------------------------------------
		// Loop for all products
		// -------------------------------------------------------------------------------		
		for(int i=0; i<stdData.size(); i++){
			
			
			// Get each STD data
			stdE = stdData.get(i);			
			
			this.logger.log("[PART NUMBER] " + stdE.getItemAt(1), LogWriter.DEBUG);
			
			
		
			// Loop for each attribute
			for(int j=0; j<this.arrAttributeList.size(); j++){
				
				// Get attribute value list by current attribute identifier
				curAttrIdentifier = this.arrAttributeList.get(j).getItemAt(1);				
				this.getCurrentAttrValList(stdE, curAttrIdentifier, curAttrValList);
				
				// multiply number of values from each attribute
				itemPartNumberCnt = itemPartNumberCnt * curAttrValList.size();
				
				curAttrValList.clear();
			}
			
			
			// Loop for generating item part number
			for(int k=0; k<itemPartNumberCnt; k++){				
				curItemList.add(this.getItemPartNumber(stdE.getItemAt(1), k+1));
			}			
			
			this.mapItemPartNumberList.put(stdE.getItemAt(1), curItemList);
			
			itemPartNumberCnt = 1;
			curItemList = new ArrayList<String>();
		
		}
		
		this.logger.log("[PART NUMBER MAP] " + this.mapItemPartNumberList.toString(), LogWriter.DEBUG);
		
		
		this.printSepLine(LogWriter.INFO);
		
	}
	
	private void generateStep2(OutputCSVFileInfoEntity outE){
		
		this.logger.log("[OUTPUT1 CSV NAME] " + outE.csvName, LogWriter.INFO);
		
		// Get data with CSV entity formed
		ArrayList<CSVEntity> stdData = this.getProductRawData();
		CSVEntity stdE = null;
				
		// Output data CSV entity
		ArrayList<CSVEntity> productData     = new ArrayList<CSVEntity>();
		ArrayList<CSVEntity> productDescData = new ArrayList<CSVEntity>();
		CSVEntity productE     = null;
		CSVEntity productDescE = null;
			
		// Final result buffer
		StringBuffer strBuf = new StringBuffer();
				
		String field5 = null;
		String weightMeasure = null;
		String defaultColor = null;
		
		// Item Part Number 
		ArrayList<String> curItemList = null;
		
		// -------------------------------------------------------------------------------
		// Phase 1 : Combine Data
		// -------------------------------------------------------------------------------
		
		for(int i=0; i<stdData.size(); i++){
			
			// Get each STD data
			stdE = stdData.get(i);			
			
			// Get Item part number of current product
			curItemList = this.mapItemPartNumberList.get(stdE.getItemAt(1));
			
			// Custom field value assignment			
			field5 = this.getDescriptionWithQuotationMark(stdE.getItemAt(11) + this.CUSTOM_FIELD_VALUE_SEPERATOR
																	         + stdE.getItemAt(12) + this.CUSTOM_FIELD_VALUE_SEPERATOR
																	         + stdE.getItemAt(13));
			
			weightMeasure = "KGM";
			defaultColor = stdE.getItemAt(15);
			
			// Mapping Procedure
			
			// -------------------------------------------------------------------------------
			// Product Data Mapping
			// -------------------------------------------------------------------------------
			
			// Create new data
			productE = new CSVEntity(this.STEP2_COLUMN_COUNT, outE.colDel);
			
			// [PRODUCT] - product field : fix value with 'product'
			productE.setItem(0, "product");
			
			// [PRODUCT] - partNumber field : [STD] PART_NUMBER
			productE.setItem(1, stdE.getItemAt(1));
			
			// [PRODUCT] - parentPartNumber field : N/A
			// Skip to mapping
			
			// [PRODUCT] - type field : fix value with 'ProductBean'
			productE.setItem(3, "ProductBean");
			
			// [PRODUCT] - markForDelete field : set to '0'
			productE.setItem(5, "0");
			
			// [PRODUCT] - weight field : [STD] WEIGHT
			productE.setItem(10, stdE.getItemAt(18));
			
			// [PRODUCT] - weightMeasure field : fixed 'kg'
			productE.setItem(11, weightMeasure);
			
			// [PRODUCT] - field2 : integer
			
			// [PRODUCT] - field3 : decimal
			
			// [PRODUCT] - field4 : 			
			
			// [PRODUCT] - field5 : [STD] LINE|MATERIAL|MADEIN|WEIGHT
			productE.setItem(16, field5);
			
			// Add to array
			productData.add(productE);
			
			// -------------------------------------------------------------------------------
			// Product Data Mapping (for Item Part Number)
			// -------------------------------------------------------------------------------
			
			for(int j=0; j<curItemList.size(); j++){
				
				// Create new data
				productE = new CSVEntity(this.STEP2_COLUMN_COUNT, outE.colDel);
				
				// [PRODUCT] - product field : fix value with 'product'
				productE.setItem(0, "product");
				
				// [PRODUCT] - partNumber field : Item PartNumber 
				productE.setItem(1, curItemList.get(j));
				
				// [PRODUCT] - parentPartNumber field : [STD] PART_NUMBER
				productE.setItem(2, stdE.getItemAt(1));
				
				// [PRODUCT] - type field : fix value with 'ProductBean'
				productE.setItem(3, "ItemBean");
				
				// [PRODUCT] - inventory field : set to '100'
				productE.setItem(4, "100");
				
				// [PRODUCT] - markForDelete field : set to '0'
				productE.setItem(5, "0");
				
				// [PRODUCT] - weight field : [STD] WEIGHT
				productE.setItem(10, stdE.getItemAt(18));
				
				// [PRODUCT] - weightMeasure field : fixed 'kg'
				productE.setItem(11, weightMeasure);
				
				// [PRODUCT] - field2 : integer
				
				// [PRODUCT] - field3 : decimal
				
				// [PRODUCT] - field4 :				
				
				// [PRODUCT] - field5 : [STD] LINE|MATERIAL|MADEIN
				productE.setItem(16, field5);
				
				// Add to array
				productData.add(productE);
			}
			
			
			
			// -------------------------------------------------------------------------------
			// Product Description Mapping
			// -------------------------------------------------------------------------------
			
			// Loop n times with each language id
			for(int inner=0; inner<LANGUAGE_ID.length; inner++){
				
				// Create new data
				productDescE = new CSVEntity(this.STEP2_COLUMN_COUNT, outE.colDel);
				
				// [PRODUCT_DESC] - productDescription field : fix value with 'productDescription'
				productDescE.setItem(0, "productDescription");
				
				// [PRODUCT_DESC] - partNumber field : [STD] PART_NUMBER
				productDescE.setItem(1, stdE.getItemAt(1));
				
				// [PRODUCT_DESC] - languageId field : LANGUAGE_ID
				productDescE.setItem(2, LANGUAGE_ID[inner]);
				
				// [PRODUCT_DESC] - displayName field : [STD] NAME
				productDescE.setItem(3, this.getDescriptionWithQuotationMark(stdE.getItemAt(9)));
				
				// [PRODUCT_DESC] - shortDescription field : [STD] SHORT_DESC
				productDescE.setItem(4, this.getDescriptionWithQuotationMark(stdE.getItemAt(10)));
				
				// [PRODUCT_DESC] - longDescription field : [STD] LONG_DESC
				productDescE.setItem(5, this.getDescriptionWithQuotationMark(stdE.getItemAt(14)));
				
				// [PRODUCT_DESC] - published field : fix value with '1'
				productDescE.setItem(6, "1");							
				
				// [PRODUCT_DESC] - thumbnail field : Prefix image path string + image file name (product list image)
				productDescE.setItem(7, this.THUMBNAIL_IMAGE_PATH + this.getImageFileNameByColor(stdE.getItemAt(20), defaultColor));
				
				// [PRODUCT_DESC] - fullImage field : Prefix image path string + image file name (full image 01)
				productDescE.setItem(8, this.FULL_IMAGE_PATH + this.getImageFileNameByColor(stdE.getItemAt(21), defaultColor));
				
				// [PRODUCT_DESC] - type field : fix value with 'ProductBean'
				productDescE.setItem(9, "ProductBean");
				
				// Add to array
				productDescData.add(productDescE);
			}			
						
			
			// -------------------------------------------------------------------------------
			// Product Description Mapping (for Item Part Number)
			// -------------------------------------------------------------------------------
			
			for(int j=0; j<curItemList.size(); j++){
							
				// Loop n times with each language id
				for(int inner=0; inner<LANGUAGE_ID.length; inner++){
					
					// Create new data
					productDescE = new CSVEntity(this.STEP2_COLUMN_COUNT, outE.colDel);
					
					// [PRODUCT_DESC] - productDescription field : fix value with 'productDescription'
					productDescE.setItem(0, "productDescription");
					
					// [PRODUCT_DESC] - partNumber field : Item Part Number
					productDescE.setItem(1, curItemList.get(j));
					
					// [PRODUCT_DESC] - languageId field : LANGUAGE_ID
					productDescE.setItem(2, LANGUAGE_ID[inner]);
					
					// [PRODUCT_DESC] - displayName field : [STD] NAME
					productDescE.setItem(3, this.getDescriptionWithQuotationMark(stdE.getItemAt(9)));
					
					// [PRODUCT_DESC] - shortDescription field : [STD] SHORT_DESC
					productDescE.setItem(4, this.getDescriptionWithQuotationMark(stdE.getItemAt(10)));
					
					// [PRODUCT_DESC] - longDescription field : [STD] LONG_DESC
					productDescE.setItem(5, this.getDescriptionWithQuotationMark(stdE.getItemAt(14)));
					
					// [PRODUCT_DESC] - published field : fix value with '1'
					productDescE.setItem(6, "1");							
					
					// [PRODUCT_DESC] - thumbnail field : Prefix image path string + image file name (thumbnail 01)
					productDescE.setItem(7, this.THUMBNAIL_IMAGE_PATH + this.getImageFileNameByColor(stdE.getItemAt(20), defaultColor));
					
					// [PRODUCT_DESC] - fullImage field : Prefix image path string + image file name (full image 01)
					productDescE.setItem(8, this.FULL_IMAGE_PATH + this.getImageFileNameByColor(stdE.getItemAt(21), defaultColor));
					
					// [PRODUCT_DESC] - type field : fix value with 'ProductBean'
					productDescE.setItem(9, "ItemBean");
					
					// Add to array
					productDescData.add(productDescE);
					
				}
				
			}
			
			
			
		}	
		
		
		// -------------------------------------------------------------------------------
		// Phase 2 : Aggregate Data
		// -------------------------------------------------------------------------------
		
		// Add header1
		strBuf.append(this.getHeaderString(HEADER_STEP2_PRODUCT, outE.colDel));
		strBuf.append("\n");
		
		// Add data
		for(int i=0; i<productData.size(); i++){
			strBuf.append(productData.get(i).toString());
			strBuf.append("\n");
		}
		
		// Add empty row
		strBuf.append(this.getEmptyRowString(STEP2_COLUMN_COUNT, outE.colDel));
		strBuf.append("\n");
		strBuf.append(this.getEmptyRowString(STEP2_COLUMN_COUNT, outE.colDel));
		strBuf.append("\n");
		
		// Add header2
		strBuf.append(this.getHeaderString(HEADER_STEP2_PRODUCT_DESC, outE.colDel));
		strBuf.append("\n");
		
		// Add data
		for(int i=0; i<productDescData.size(); i++){
			strBuf.append(productDescData.get(i).toString());
			strBuf.append("\n");
		}
		
		
		// -------------------------------------------------------------------------------
		// Phase 3 : Write to new output CSV File
		// -------------------------------------------------------------------------------	
		
		// Write to File
		this.writeToFile(outE, strBuf.toString());	
				
		
		this.printSepLine(LogWriter.INFO);
		
	}
	
	private void generateStep3(OutputCSVFileInfoEntity outE){
		
		this.logger.log("[OUTPUT2 CSV NAME] " + outE.csvName, LogWriter.INFO);
		
		// Get data with CSV entity formed
		ArrayList<CSVEntity> stdData = this.getProductRawData();
		CSVEntity stdE = null;
				
		// Output data CSV entity
		ArrayList<CSVEntity> categoryProductRelationData = new ArrayList<CSVEntity>();
		CSVEntity catProdRelE = null;
				
		// Final result buffer
		StringBuffer strBuf = new StringBuffer();
		
		// Item Part Number 
		ArrayList<String> curItemList = null;
		
		// Category 
		String curCategory = null;
		
		// -------------------------------------------------------------------------------
		// Phase 1 : Combine Data
		// -------------------------------------------------------------------------------
		
		for(int i=0; i<stdData.size(); i++){
			
			// Get each STD data
			stdE = stdData.get(i);
			
			// Get Category
			curCategory = this.getCatProdRelCategoryName(stdE.getItemAt(3),stdE.getItemAt(4));
			
			// Get Item part number of current product
			curItemList = this.mapItemPartNumberList.get(stdE.getItemAt(1));
			
			// Mapping Procedure
			
			// -------------------------------------------------------------------------------
			// Category Product Relation Data Mapping
			// -------------------------------------------------------------------------------
			
			// Create new data
			catProdRelE = new CSVEntity(this.STEP3_COLUMN_COUNT, outE.colDel);
			
			// [CATEGORY_PRODUCT_REL] - categoryProductRelation field : fix value with 'categoryProductRelation'
			catProdRelE.setItem(0, "categoryProductRelation");
			
			// [CATEGORY_PRODUCT_REL] - categoryName field : [STD] CATEGORY + SUB_CATEGORY
			catProdRelE.setItem(1, curCategory);
			
			// [CATEGORY_PRODUCT_REL] - categoryMemberId field : N/A
			// Skip to mapping
			
			// [CATEGORY_PRODUCT_REL] - partNumber field : [STD} PART_NUMBER
			catProdRelE.setItem(3, stdE.getItemAt(1));
			
			// [CATEGORY_PRODUCT_REL] - sequence field : fix value with '1'
			catProdRelE.setItem(4, "1");
			
			// Add to array
			categoryProductRelationData.add(catProdRelE);
			
			
			// -------------------------------------------------------------------------------
			// Category Product Relation Data Mapping (for Item Part Number)
			// -------------------------------------------------------------------------------
			
			for(int j=0; j<curItemList.size(); j++){
			
				// Create new data
				catProdRelE = new CSVEntity(this.STEP3_COLUMN_COUNT, outE.colDel);
				
				// [CATEGORY_PRODUCT_REL] - categoryProductRelation field : fix value with 'categoryProductRelation'
				catProdRelE.setItem(0, "categoryProductRelation");
				
				// [CATEGORY_PRODUCT_REL] - categoryName field : [STD] CATEGORY + SUB_CATEGORY
				catProdRelE.setItem(1, curCategory);
				
				// [CATEGORY_PRODUCT_REL] - categoryMemberId field : N/A
				// Skip to mapping
				
				// [CATEGORY_PRODUCT_REL] - partNumber field : [STD} PART_NUMBER
				catProdRelE.setItem(3, curItemList.get(j));
				
				// [CATEGORY_PRODUCT_REL] - sequence field : fix value with '1'
				catProdRelE.setItem(4, "1");
				
				// Add to array
				categoryProductRelationData.add(catProdRelE);
				
			}
		
		}
		
		
		// -------------------------------------------------------------------------------
		// Phase 2 : Aggregate Data
		// -------------------------------------------------------------------------------
		
		// Add header1
		strBuf.append(this.getHeaderString(HEADER_STEP3_CATEGORY_PRODUCT_REL, outE.colDel));
		strBuf.append("\n");
		
		// Add data
		for(int i=0; i<categoryProductRelationData.size(); i++){
			strBuf.append(categoryProductRelationData.get(i).toString());
			strBuf.append("\n");
		}	
		
		
		// -------------------------------------------------------------------------------
		// Phase 3 : Write to new output CSV File
		// -------------------------------------------------------------------------------	
		
		// Write to File
		this.writeToFile(outE, strBuf.toString());
		
		
		this.printSepLine(LogWriter.INFO);
		
	}
	
	private void generateStep5(OutputCSVFileInfoEntity outE){
		
		this.logger.log("[OUTPUT3 CSV NAME] " + outE.csvName, LogWriter.INFO);
		
		// Get data with CSV entity formed
		ArrayList<CSVEntity> stdData = this.getProductRawData();
		CSVEntity stdE = null;
				
		// Output data CSV entity
		ArrayList<CSVEntity> attributeData      = new ArrayList<CSVEntity>();
		ArrayList<CSVEntity> attributeValueData = new ArrayList<CSVEntity>();
		CSVEntity attrE = null;
		CSVEntity attrValE = null;
				
		String curAttrIdentifier = null;		
		ArrayList<String> curAttrValList = new ArrayList<String>();
		
		// Use for SKU Generation
		HashMap<String,ArrayList<String>> attrMap = new HashMap<String,ArrayList<String>>();
		ArrayList<String> attrMapMember = null;
		
		// Definition for SKU generation
		ArrayList<String> arrColorVal = null;
		ArrayList<String> arrSizeVal = null;
		
		CSVEntity attrColorValE = null;
		CSVEntity attrSizeValE  = null;
		
		String attrIdentifier1 = null;
		String attrName1 = null;
		
		String attrIdentifier2 = null;
		String attrName2 = null;
		
		int itemPartNumCnt;
		ArrayList<String> curItemList = null;
								
		// Final result buffer
		StringBuffer strBuf = new StringBuffer();
		
		// -------------------------------------------------------------------------------
		// Phase 1 : Combine Data
		// -------------------------------------------------------------------------------
		
		for(int i=0; i<stdData.size(); i++){
			
			// Get each STD data
			stdE = stdData.get(i);
			
			// Mapping Procedure
			
			// -------------------------------------------------------------------------------
			// Attribute Data Mapping
			// -------------------------------------------------------------------------------
			
			// Loop for each attribute
			for(int j=0; j<this.arrAttributeList.size(); j++){
				
				// Loop for each language id
				for(int k=0; k<this.LANGUAGE_ID.length; k++){
					
					// Create new data
					attrE = new CSVEntity(this.STEP5_COLUMN_COUNT, outE.colDel);
					
					// [ATTRIBUTE] - attribute field : fix value with 'attribute'
					attrE.setItem(0, "attribute");
					
					// [ATTRIBUTE] - parentPartNumber field : [STD] PART_NUMBER
					attrE.setItem(1, stdE.getItemAt(1));
					
					// [ATTRIBUTE] - languageId field : LANGUAGE_ID
					attrE.setItem(2, this.LANGUAGE_ID[k]);
					
					// [ATTRIBUTE] - attributeType field : fix value with 'STRING'
					attrE.setItem(3, "STRING");
					
					// [ATTRIBUTE] - attributeName field : arrAttributeList CSV - 2
					attrE.setItem(4, this.arrAttributeList.get(j).getItemAt(2));
					
					// [ATTRIBUTE] - description,description2 field : N/A
					// Skip to mapping
					
					// [ATTRIBUTE] - sequence field : arrAttributeList CSV - 0
					attrE.setItem(7, this.arrAttributeList.get(j).getItemAt(0));
					
					// [ATTRIBUTE] - field1 field : N/A
					// Skip to mapping
					
					// [ATTRIBUTE] - attributeIdentifier field : arrAttributeList CSV - 1
					attrE.setItem(9, this.arrAttributeList.get(j).getItemAt(1));
					
					
					// Add to array
					attributeData.add(attrE);
				
				} // k
				
			} // j

			
			// -------------------------------------------------------------------------------
			// Attribute Value Data Mapping
			// -------------------------------------------------------------------------------
			
			// Loop for each attribute
			for(int j=0; j<this.arrAttributeList.size(); j++){
				
				// Get attribute value list by current attribute identifier
				curAttrIdentifier = this.arrAttributeList.get(j).getItemAt(1);
				
				this.getCurrentAttrValList(stdE, curAttrIdentifier, curAttrValList);
								
				// Make attribute map for generating SKU
				attrMapMember = (ArrayList<String>) curAttrValList.clone();
				attrMap.put(curAttrIdentifier, attrMapMember);				
				
				// Loop for each attribute value
				for(int k=0; k<curAttrValList.size(); k++){
				
					// Loop for each language id
					for(int z=0; z<this.LANGUAGE_ID.length; z++){
				
						// Create new data
						attrValE = new CSVEntity(this.STEP5_COLUMN_COUNT, outE.colDel);
						
						// [ATTRIBUTE_VALUE] - attributeValue field : fix value with 'attributeValue'
						attrValE.setItem(0, "attributeValue");
						
						// [ATTRIBUTE_VALUE] - itemPartNumber : N/A
						// Skip to mapping
						
						// [ATTRIBUTE_VALUE] - parentPartNumber field : [STD] PART_NUMBER
						attrValE.setItem(2, stdE.getItemAt(1));
						
						// [ATTRIBUTE_VALUE] - languageId : LANGUAGE_ID
						attrValE.setItem(3, this.LANGUAGE_ID[z]);
						
						// [ATTRIBUTE_VALUE] - attributeType field : fix value with 'STRING'
						attrValE.setItem(4, "STRING");
						
						// [ATTRIBUTE_NAME] - attributeName : arrAttributeList CSV - 2					
						attrValE.setItem(5, this.arrAttributeList.get(j).getItemAt(2));
						
						// [ATTRIBUTE_VALUE] - attributeValue : [STD] Get value from (COLOR,SIZE) by attributeIdentifier
						// 6
						attrValE.setItem(6, this.getDescriptionWithQuotationMark(curAttrValList.get(k)));
						
						// [ATTRIBUTE_VALUE] - sequence : [STD] Get sequence from current attribute value array (seq must start with 1)
						attrValE.setItem(7, String.valueOf(k+1));
						
						// [ATTRIBUTE_VALUE] - field1 field : N/A
						// Skip to mapping
						
						// [ATTRIBUTE_VALUE] - attributeIdentifier : arrAttributeList CSV - 1					
						attrValE.setItem(9, this.arrAttributeList.get(j).getItemAt(1));
						
						// [ATTRIBUTE_VALUE] - attributeValueIdentifier : Same as attributeValue						
						attrValE.setItem(10, attrValE.getItemAt(6));
						
						// Add to array
						attributeValueData.add(attrValE);					
				
					} // z
				
				} // k
				
				curAttrValList.clear();
				
			} // j
			
			
			// -------------------------------------------------------------------------------
			// SKU Data Generation (Color, Size only)
			// -------------------------------------------------------------------------------
					
			
			// Get color and size attribute identifier and display name
			attrIdentifier1 = this.arrAttributeList.get(0).getItemAt(1);
			attrName1       = this.arrAttributeList.get(0).getItemAt(2);
						
			attrIdentifier2 = this.arrAttributeList.get(1).getItemAt(1);
			attrName2       = this.arrAttributeList.get(1).getItemAt(2);
					
			
			// Get color and size values from attribute map
			arrColorVal = attrMap.get(attrIdentifier1);
			arrSizeVal  = attrMap.get(attrIdentifier2);
			
			
			// SKU start
			itemPartNumCnt = 0;	
			
			// Get Item Part Number list from map
			curItemList = this.mapItemPartNumberList.get(stdE.getItemAt(1));	
			
			
			// Nested loop for second attribute value
			
			// Generate itemPartNumber and assign attribute values 
			
			// Loop for each attribute value by nested loop
			for(int j=0; j<arrColorVal.size(); j++){
				
				
				
				// Loop for size values and write down color/size pair
				for(int k=0; k<arrSizeVal.size(); k++){
					
					// Loop for each language id (color attr looping)
					for(int z=0; z<this.LANGUAGE_ID.length; z++){
					
						// Create new data
						attrColorValE = new CSVEntity(this.STEP5_COLUMN_COUNT, outE.colDel);
						
						// [ATTRIBUTE_VALUE] - attributeValue field : fix value with 'attributeValue'
						attrColorValE.setItem(0, "attributeValue");			
						
						// [ATTRIBUTE_VALUE] - itemPartNumber : 
						attrColorValE.setItem(1, curItemList.get(itemPartNumCnt));
						
						// [ATTRIBUTE_VALUE] - parentPartNumber field : [STD] PART_NUMBER
						attrColorValE.setItem(2, stdE.getItemAt(1));
						
						// [ATTRIBUTE_VALUE] - languageId : LANGUAGE_ID
						attrColorValE.setItem(3, this.LANGUAGE_ID[z]);
						
						// [ATTRIBUTE_VALUE] - attributeType field : fix value with 'STRING'
						attrColorValE.setItem(4, "STRING");
						
						// [ATTRIBUTE_NAME] - attributeName : arrAttributeList CSV - 2					
						attrColorValE.setItem(5, attrName1);
						
						// [ATTRIBUTE_VALUE] - attributeValue : [STD] Get value from (COLOR,SIZE) by attributeIdentifier
						attrColorValE.setItem(6, this.getDescriptionWithQuotationMark(arrColorVal.get(j)));
						
						// [ATTRIBUTE_VALUE] - sequence : [STD] Get sequence from current attribute value array (seq must start with 1)
						attrColorValE.setItem(7, String.valueOf(j+1));
												
						// [ATTRIBUTE_VALUE] - attributeIdentifier : arrAttributeList CSV - 1					
						attrColorValE.setItem(9, attrIdentifier1);
						
						// [ATTRIBUTE_VALUE] - attributeValueIdentifier : Same as attributeValue						
						attrColorValE.setItem(10, attrColorValE.getItemAt(6));
						
						// Add to array
						attributeValueData.add(attrColorValE);
					
					} // z
					
					
					// Loop for each language id (size attr looping)
					for(int z=0; z<this.LANGUAGE_ID.length; z++){
					
						// Create new data
						attrSizeValE = new CSVEntity(this.STEP5_COLUMN_COUNT, outE.colDel);
						
						// [ATTRIBUTE_VALUE] - attributeValue field : fix value with 'attributeValue'
						attrSizeValE.setItem(0, "attributeValue");			
						
						// [ATTRIBUTE_VALUE] - itemPartNumber : N/A
						attrSizeValE.setItem(1, curItemList.get(itemPartNumCnt));
						
						// [ATTRIBUTE_VALUE] - parentPartNumber field : [STD] PART_NUMBER
						attrSizeValE.setItem(2, stdE.getItemAt(1));
						
						// [ATTRIBUTE_VALUE] - languageId : LANGUAGE_ID
						attrSizeValE.setItem(3, this.LANGUAGE_ID[z]);
						
						// [ATTRIBUTE_VALUE] - attributeType field : fix value with 'STRING'
						attrSizeValE.setItem(4, "STRING");
						
						// [ATTRIBUTE_NAME] - attributeName : arrAttributeList CSV - 2					
						attrSizeValE.setItem(5, attrName2);
						
						// [ATTRIBUTE_VALUE] - attributeValue : [STD] Get value from (COLOR,SIZE) by attributeIdentifier
						attrSizeValE.setItem(6, this.getDescriptionWithQuotationMark(arrSizeVal.get(k)));
						
						// [ATTRIBUTE_VALUE] - sequence : [STD] Get sequence from current attribute value array (seq must start with 1)
						attrSizeValE.setItem(7, String.valueOf(k+1));
												
						// [ATTRIBUTE_VALUE] - attributeIdentifier : arrAttributeList CSV - 1					
						attrSizeValE.setItem(9, attrIdentifier2);
						
						// [ATTRIBUTE_VALUE] - attributeValueIdentifier : Same as attributeValue						
						attrSizeValE.setItem(10, attrSizeValE.getItemAt(6));
											
						// Add to array
						attributeValueData.add(attrSizeValE);
					
					} // z
					
					
					// Increase item part number count
					itemPartNumCnt++;
					
				} // k
				
				
				
			} // j
			
			attrMap.clear();
			
		}
		
		// -------------------------------------------------------------------------------
		// Phase 2 : Aggregate Data
		// -------------------------------------------------------------------------------
		
		// Add header1
		strBuf.append(this.getHeaderString(HEADER_STEP5_ATTRIBUTE, outE.colDel));
		strBuf.append("\n");
		
		// Add product data
		for(int i=0; i<attributeData.size(); i++){
			strBuf.append(attributeData.get(i).toString());
			strBuf.append("\n");
		}	
		
		// Add empty row
		strBuf.append(this.getEmptyRowString(STEP2_COLUMN_COUNT, outE.colDel));
		strBuf.append("\n");
		strBuf.append(this.getEmptyRowString(STEP2_COLUMN_COUNT, outE.colDel));
		strBuf.append("\n");
		
		// Add header1
		strBuf.append(this.getHeaderString(HEADER_STEP5_ATTRIBUTE_VALUE, outE.colDel));
		strBuf.append("\n");
		
		// Add product data
		for(int i=0; i<attributeValueData.size(); i++){
			strBuf.append(attributeValueData.get(i).toString());
			strBuf.append("\n");
		}
		
		
		// -------------------------------------------------------------------------------
		// Phase 3 : Write to new output CSV File
		// -------------------------------------------------------------------------------	
		
		// Write to File
		this.writeToFile(outE, strBuf.toString());
		
		
		this.printSepLine(LogWriter.INFO);
		
	}
	
	private String getItemPartNumber(String partNumber, int idx){
		return partNumber + Utility.fixLength(String.valueOf(idx),3, 0, '0');
	}
	
	private void generateOfferPrice(OutputCSVFileInfoEntity outE){
		
		this.logger.log("[OUTPUT4 CSV NAME] " + outE.csvName, LogWriter.INFO);
		
		// Get data with CSV entity formed
		ArrayList<CSVEntity> stdData = this.getProductRawData();
		CSVEntity stdE = null;
				
		// Output data CSV entity
		ArrayList<CSVEntity> priceData = new ArrayList<CSVEntity>();
		CSVEntity priceE = null;
				
		
		// Final result buffer
		StringBuffer strBuf = new StringBuffer();
		
		// -------------------------------------------------------------------------------
		// Phase 1 : Combine Data
		// -------------------------------------------------------------------------------
		
		for(int i=0; i<stdData.size(); i++){
			
			// Get each STD data
			stdE = stdData.get(i);			
			
			// Mapping Procedure
			
			// -------------------------------------------------------------------------------
			// Product Data Mapping
			// -------------------------------------------------------------------------------
			
			// Create new data
			priceE = new CSVEntity(this.OFFER_PRICE_COLUMN_COUNT, outE.colDel);
									
			// [PRODUCT] - PartNumber field : [STD] PART_NUMBER
			priceE.setItem(0, stdE.getItemAt(1));
			
			// [PRODUCT] - Price field : [STD] OFFER_PRICE
			priceE.setItem(1, stdE.getItemAt(7));
			
			// [PRODUCT] - CurrencyCode field : [STD] CURRENCY_CODE
			priceE.setItem(2, stdE.getItemAt(5));
			
			// [PRODUCT] - MinimumQuantity field : fix value with '1'
			priceE.setItem(3, "1");
			
			// [PRODUCT] - MaximumQuantity fields : N/A
	    	// Skip to mapping
			
			// [PRODUCT] - Delete field : fix value with '0'
			priceE.setItem(5, "0");
			
			// Add to array
			priceData.add(priceE);			
			
		}
		
		
		// -------------------------------------------------------------------------------
		// Phase 2 : Aggregate Data
		// -------------------------------------------------------------------------------
		
		// Add meta name
		priceE = new CSVEntity(this.OFFER_PRICE_COLUMN_COUNT, outE.colDel);
		priceE.setItem(0, "CatalogEntryOfferPrice");
		strBuf.append(priceE);
		strBuf.append("\n");
		
		// Add header1
		strBuf.append(this.getHeaderString(this.HEADER_OFFER_PRICE, outE.colDel));
		strBuf.append("\n");
		
		// Add data
		for(int i=0; i<priceData.size(); i++){
			strBuf.append(priceData.get(i).toString());
			strBuf.append("\n");
		}
		
		
		// -------------------------------------------------------------------------------
		// Phase 3 : Write to new output CSV File
		// -------------------------------------------------------------------------------	
		
		// Write to File
		this.writeToFile(outE, strBuf.toString());	
				
		
		this.printSepLine(LogWriter.INFO);
		
	}
	
	private void generateAssetReference(OutputCSVFileInfoEntity outE){
			
		this.logger.log("[OUTPUT5 CSV NAME] " + outE.csvName, LogWriter.INFO);
		
		// Get data with CSV entity formed
		ArrayList<CSVEntity> stdData = this.getProductRawData();
		CSVEntity stdE = null;
				
		// Output data CSV entity
		ArrayList<CSVEntity> assetList = new ArrayList<CSVEntity>();			
		CSVEntity colorE = null;
		
		String curColor = null;
		String thumbImageList = null;
		String fullImageList = null;
						
		// Final result buffer
		StringBuffer strBuf = new StringBuffer();
		
		// -------------------------------------------------------------------------------
		// Phase 1 : Combine Data
		// -------------------------------------------------------------------------------
		
		for(int i=0; i<stdData.size(); i++){
			
			// Get each STD data
			stdE = stdData.get(i);
			
			// Get default color
			curColor = stdE.getItemAt(15);
			
			// Mapping Procedure
			
			// -------------------------------------------------------------------------------
			// Add Product Information
			// -------------------------------------------------------------------------------
			
			// Show product part number and name
			strBuf.append(stdE.getItemAt(1) + outE.colDel + stdE.getItemAt(9));
			strBuf.append("\n");
			
			// Show product default color
			strBuf.append("Product" + outE.colDel + "Default Color : " + curColor);
			strBuf.append("\n");
			
			// Product Image Asset				
			thumbImageList = stdE.getItemAt(20);
			fullImageList = stdE.getItemAt(21);
						
			assetList = this.getImageFileNameListByColor(thumbImageList, fullImageList, curColor);
			
			// Make asset reference text
			this.makeAssetReferenceText(strBuf, assetList, outE.colDel);
			
			// SKU Image Asset by Color
			
			// Get all colors
			colorE = new CSVEntity(stdE.getItemAt(16),this.getRAWCSVFileInfo().colInfoArray.get(16).multipleValDelim);
			
			for(int k=0; k<colorE.getItemCount(); k++){
				
				// Get each color
				curColor = colorE.getItemAt(k);
				
				// Get asset list by each color
				assetList = this.getImageFileNameListByColor(thumbImageList, fullImageList, curColor);
				
				strBuf.append("SKU - " + curColor + "\n");
				
				// Make asset reference text
				this.makeAssetReferenceText(strBuf, assetList, outE.colDel);
				
			}								
			
			// Add seperator line
			strBuf.append("\n\n");			
			
			
		}
		
		
		// -------------------------------------------------------------------------------
		// Phase 2 : Write to new output CSV File
		// -------------------------------------------------------------------------------	
		
		// Write to File
		this.writeToFile(outE, strBuf.toString());
		
		
		this.printSepLine(LogWriter.INFO);
	}
	
	private void generateImageCheckDocument(OutputCSVFileInfoEntity outE){
		
		this.logger.log("[OUTPUT6 CSV NAME] " + outE.csvName, LogWriter.INFO);
		
		// Get data with CSV entity formed
		ArrayList<CSVEntity> stdData = this.getProductRawData();
		CSVEntity stdE = null;
		
		// Final result buffer
		StringBuffer strBuf = new StringBuffer();
		
		// HTML base tag
		strBuf.append("<html>\n");
		strBuf.append("<title>Image Check for MCM Products</title>\n");
		strBuf.append("<body>\n");		
		
		// -------------------------------------------------------------------------------
		// Phase 1 : Combine Data
		// -------------------------------------------------------------------------------
		
		for(int i=0; i<stdData.size(); i++){
			
			// Get each STD data
			stdE = stdData.get(i);
			
			// Add product info
			strBuf.append("<p><font size='+1'>[" + stdE.getItemAt(5) + "] " + stdE.getItemAt(6) + "</font></p>\n");
			
			// Add image url to buffer
			strBuf.append(this.getDisysImageURL(stdE.getItemAt(10)));
			strBuf.append("<br>\n");
			
		}
		
		strBuf.append("</body>\n");
		strBuf.append("</html>\n");
		
		
		// -------------------------------------------------------------------------------
		// Phase 2 : Write to new output CSV File
		// -------------------------------------------------------------------------------	
		
		// Write to File
		this.writeToFile(outE, strBuf.toString());
		
		
		this.printSepLine(LogWriter.INFO);
		
	}
	
	private String getDisysImageURL(String longDesc){
		
		int startIdx = longDesc.indexOf("http://");
		
		if( startIdx > 0) return "<img src='" +  longDesc.substring(startIdx) + "'>";
		else return "<img src='****' width='300' height='300'>";
		
	}
	
	private void makeAssetReferenceText(StringBuffer strBuf, ArrayList<CSVEntity> assetList, String colDel){
		
		CSVEntity assetE = null;
		
		for(int j=0; j<assetList.size(); j++){
			
			assetE = assetList.get(j);
			
			if(!assetE.getItemAt(0).startsWith("**")){
			
				strBuf.append(j+1);
				strBuf.append(colDel);
				strBuf.append(this.THUMBNAIL_IMAGE_PATH + assetE.getItemAt(0));
				strBuf.append(colDel);
				strBuf.append("ANGLEIMAGES_THUMBNAIL");
				strBuf.append("\n");
				
				strBuf.append(j+1);
				strBuf.append(colDel);
				strBuf.append(this.FULL_IMAGE_PATH + assetE.getItemAt(1));
				strBuf.append(colDel);
				strBuf.append("ANGLEIMAGES_FULLIMAGE");
				strBuf.append("\n");
				
				// --- Skip to write zoom image info ---
				
				//strBuf.append(j+1);
				//strBuf.append(colDel);
				//strBuf.append(this.ZOOM_IMAGE_PATH + assetE.getItemAt(2));
				//strBuf.append(colDel);
				//strBuf.append("ANGLEIMAGES_FULLIMAGE");
				//strBuf.append("\n");
				
				// --- Skip to write zoom image info ---
			
			}else {
								
				strBuf.append(assetE.getItemAt(0));
				strBuf.append("\n");
								
				strBuf.append(assetE.getItemAt(1));
				strBuf.append("\n");
								
				strBuf.append(assetE.getItemAt(2));
				strBuf.append("\n");
			}
			
		}
	}
	
	private String getDescriptionWithQuotationMark(String text){		
		return "\"" + text + "\"";
	}
	
	private void getCurrentAttrValList(CSVEntity row, String curAttrIdentifier, ArrayList<String> curAttrValList){
		
		this.logger.log("[CURRENT ATTR_ID] " + curAttrIdentifier, LogWriter.DEBUG);
		
		String valList = "";
		String valDelim = "";
		int idx = 0;
		
		CSVEntity valE = null;
		
		// Get attribute value list by attribute identifier
		if(curAttrIdentifier.equals("COLOR")){
			idx = 16;
		}else if(curAttrIdentifier.equals("SIZE")){
			idx = 17;
		}
		
		valList = row.getItemAt(idx);
		valDelim = this.getRAWCSVFileInfo().colInfoArray.get(idx).multipleValDelim;
		
		this.logger.log("[CURRENT ATTR_VAL] " + valList, LogWriter.DEBUG);
		this.logger.log("[CURRENT ATTR_DELIM] " + valDelim, LogWriter.DEBUG);
		
		valE = new CSVEntity(valList, valDelim);
		
		for(int i=0; i<valE.getItemCount(); i++){
			curAttrValList.add(valE.getItemAt(i));
		}
		
	}
	
	private RAWCSVFileInfoEntity getRAWCSVFileInfo(){
		return this.rawCsvM.getCSVfileInfoByIndex(0);
	}
	
	private String getIdentifierByDisplayName(String displayName){
		
		CSVEntity csvE = null;
		
		for(int i=0; i<this.arrIdentifierList.size(); i++){
			
			csvE = this.arrIdentifierList.get(i);
			
			if(csvE.getItemAt(1).equals(displayName)) return csvE.getItemAt(0);
		}
		
		return displayName;
	}
	
	private String getCatProdRelCategoryName(String category, String subCategory){
		
		String cat = this.getIdentifierByDisplayName(category); 
		
		return  cat
		      + (cat.length() > 0 ? this.CATEGORY_NAME_COMBINATOR : "") 
		      + this.getIdentifierByDisplayName(subCategory);
	}
	
	private String getImageFileNameByColor(String imageList, String defaultColor){
		
		// Get seperated image list from string with default multi value delimiter from color field
		CSVEntity csvE = new CSVEntity(imageList, this.getRAWCSVFileInfo().colInfoArray.get(16).multipleValDelim);
		
		// Remove space from color name
		defaultColor = Utility.replaceAll(defaultColor, " ", "");
		
		this.logger.log("[IMAGE LIST] " + imageList, LogWriter.DEBUG);
		this.logger.log("[COLOR] " + defaultColor, LogWriter.DEBUG);
		
		// Check default color is set or not and find item
		if(defaultColor.trim().length() > 0){
			
			for(int i=0; i<csvE.getItemCount(); i++){
				if(csvE.getItemAt(i).contains(defaultColor)) return csvE.getItemAt(i);
			}
			
			// Not found on loop
			if(csvE.getItemAt(0) != null) return csvE.getItemAt(0);
			else return "";
			
		}else {
			// Have no default color
			if(csvE.getItemAt(0) != null) return csvE.getItemAt(0);
			else return "";
		}
		
	}
	
	private ArrayList<CSVEntity> getImageFileNameListByColor(String thumbImageList, String fullImageList, String curColor){
				
		CSVEntity csvE = null;
		
		ArrayList<CSVEntity> arrList = new ArrayList<CSVEntity>();
		
		CSVEntity thumbE = new CSVEntity(thumbImageList, this.getRAWCSVFileInfo().colInfoArray.get(20).multipleValDelim);
		CSVEntity fullE = new CSVEntity(fullImageList, this.getRAWCSVFileInfo().colInfoArray.get(21).multipleValDelim);				
		
		// Check validation of num of images
		if(thumbE.getItemCount() != fullE.getItemCount()){
			this.logger.log("[MISMATCH NUMBER OF IMAGE FILE NAME] " + thumbE, LogWriter.ERROR);			
		}
		
		// Remove space from color name
		curColor = Utility.replaceAll(curColor, " ", "");
						
		// Check color is set or not and find item
		if(curColor.trim().length() > 0){
			
			for(int i=0; i<thumbE.getItemCount(); i++){
				if(thumbE.getItemAt(i).contains(curColor)){
					
					csvE = new CSVEntity(2,",");
					
					csvE.setItem(0, thumbE.getItemAt(i));
					csvE.setItem(1, fullE.getItemAt(i));
					
					this.logger.log("[COLOR] " + curColor, LogWriter.DEBUG);
					
					this.logger.log("[THUMB IMAGET] " + thumbE.getItemAt(i), LogWriter.DEBUG);
					this.logger.log("[FULL IMAGE] " + fullE.getItemAt(i), LogWriter.DEBUG);					
					
					arrList.add(csvE);
				}
			}					
			
		}
		
		// Check color list is not exist
		if(arrList.size() == 0){
			csvE = new CSVEntity(3,",");
			
			csvE.setItem(0, "**************************");
			csvE.setItem(1, "<IMAGE FILE NAME MISMATCH>");
			csvE.setItem(2, "**************************");
			
			arrList.add(csvE);
			
		}
		
		return arrList;
		
	}
	
	private void writeToFile(OutputCSVFileInfoEntity outE, String text){
		
		this.logger.log("[WRITE TO FILE]\n" + text, LogWriter.DEBUG);
		
		BufferedWriter csvFile = null;
		
		try{
			
			// Open new file for write
			csvFile = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outE.fileName),outE.encode));
			csvFile.write(text);
			
			this.logger.log("[FILE SAVED] " + outE.fileName, LogWriter.INFO);
			
		}catch(IOException ioe){
			this.logger.log("[OUTPUT_CSV_FILE_ERR] -> " + ioe.toString(), LogWriter.ERROR);
		}catch(Exception e){
			this.logger.log("[ILLEGAL_EXCEPTION] -> " + e.toString(), LogWriter.ERROR);
		}finally{    	
			try{
				if(csvFile != null) csvFile.close();    				
			}catch(Exception e){    				
			}		
			
		}
		
	}
	
	private ArrayList<CSVEntity> getProductRawData(){
		if(this.arrSTDFile.get(0) != null) return (ArrayList<CSVEntity>) this.arrSTDFile.get(0);
		else return null;
	}
	
	private void loadStandardCSVFile(){
		
		// Temp entity
    	RAWCSVFileInfoEntity fileInfo = null;    	    	  	
    	BufferedReader stdFile = null;
    	String nextLine = null;
    	
    	ArrayList<CSVEntity> arrCSVContent = null;
    	CSVEntity csvE = null;

    	int csvCnt = this.rawCsvM.getFileCount();
    	
    	for(int i=0; i < csvCnt; i++){
    		
    		// Get CSV file info
    		fileInfo = rawCsvM.getCSVfileInfoByIndex(i);
    		
    		// Process only enabled CSV info
    		if(fileInfo.isEnabled){
    			
    			arrCSVContent = new ArrayList<CSVEntity>();
    			
    			printSepLine(LogWriter.INFO);
    			this.logger.log("[STD CSV] : " + fileInfo.fileName+this.stdInfoM.getCSVfileInfo().postfix, LogWriter.INFO);
    			
    			try{
    				// Read STD CSV file with given encode value
    				stdFile = new BufferedReader(new InputStreamReader(new FileInputStream(fileInfo.fileName+this.stdInfoM.getCSVfileInfo().postfix),fileInfo.encode));
    				    				
    				// Add each line to CSV entity
    				while((nextLine = stdFile.readLine()) != null){
    					
    					csvE = new CSVEntity(nextLine, this.stdInfoM.getCSVfileInfo().colDel);
    					arrCSVContent.add(csvE);
    					
    				}
    				
    				// Add CSV entity array to file repository
    				this.arrSTDFile.add(arrCSVContent);
    				
    			}catch(IOException ioe){
    				this.logger.log("[CSV_FILE_ERR] -> " + ioe.toString(), LogWriter.ERROR);
    			}catch(Exception e){
    				this.logger.log("[ILLEGAL_EXCEPTION] -> " + e.toString(), LogWriter.ERROR);
    			}finally{
    				try{
    					if(stdFile != null) stdFile.close();    				
    				}catch(Exception e){    				
    				}
    				
    			}
    		}    		
    	}
    	
    	
	}
	
	private String getEmptyRowString(int colCount, String delimiter){
		return (new CSVEntity(colCount, delimiter)).toString();
	}
	
	private String getHeaderString(String[] header, String delimiter){
		
		StringBuffer strBuf = new StringBuffer();
		boolean isFirst = true;
		
		for(int i=0; i<header.length; i++){
		
			if(!isFirst) strBuf.append(delimiter);
			else isFirst = false;
			
			strBuf.append(header[i]);
		}		
		
		return strBuf.toString();
	}
	
	private void printSepLine(int logLevel){
		this.logger.logPureText("\n--------------------------------------------------------------------------\n", logLevel);
    }

}
